﻿using System.Collections.Generic;
using System.Linq;
using LCA.Community.DAL.Interfaces;
using LCA.Community.DAL.Model;
using LCA.Community.DAL.Test.ModelFactories;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using LCA.Community.DAL;
using System;

namespace LCA.Community.DAL.Test
{
    /// <summary>
    ///This is a test class for UsersRepositoryTest and is intended
    ///to contain all UsersRepositoryTest Unit Tests
    ///</summary>
    [TestClass()]
    public class UsersRepositoryTest : BaseTestClass
    {
        #region Fields
        private List<User> _users;
        private UsersFactory _usersFactory = new UsersFactory();
        private List<User> _helpedUsers;
        private List<User> _volunteers;
        private List<HelpRelationship> _helpRealtionships;
        private HelpRelationshipFactory _helpRelationshipFactory = new HelpRelationshipFactory();
        #endregion

        /// <summary>
        /// Initializes the test.
        /// </summary>
        [TestInitialize()]
        public void InitializeTest()
        {
            UnityContainerInitializer();

            var usersRepository = _unityContainer.Resolve<IUsersRepository>();
            _users = _usersFactory.CreateList(10);
            _users.ForEach(user => usersRepository.Add(user));

            var helpRelationshipRepository = _unityContainer.Resolve<IHelpRelationshipsRepository>();
            HelpRelationship hr;
            _helpedUsers = new List<User>();
            _volunteers = new List<User>();
            _helpRealtionships = new List<HelpRelationship>();

            hr = _helpRelationshipFactory.CreateEntity(_users[0].RowKey, _users[1].RowKey);
            _volunteers.Add(_users[0]);
            _helpedUsers.Add(_users[1]);
            helpRelationshipRepository.Add(hr);
            _helpRealtionships.Add(hr);

            hr = _helpRelationshipFactory.CreateEntity(_users[3].RowKey, _users[1].RowKey);
            _volunteers.Add(_users[3]);
            helpRelationshipRepository.Add(hr);
            _helpRealtionships.Add(hr);

            hr = _helpRelationshipFactory.CreateEntity(_users[0].RowKey, _users[2].RowKey);
            _helpedUsers.Add(_users[2]);
            helpRelationshipRepository.Add(hr);
            _helpRealtionships.Add(hr);

            hr = _helpRelationshipFactory.CreateEntity(_users[3].RowKey, _users[4].RowKey);
            _helpedUsers.Add(_users[4]);
            helpRelationshipRepository.Add(hr);
            _helpRealtionships.Add(hr);
        }

        /// <summary>
        /// Cleans up the test.
        /// </summary>
        [TestCleanup()]
        public void CleanupTest()
        {
            var usersRepository = _unityContainer.Resolve<IUsersRepository>();
            var helpRelationshipRepository = _unityContainer.Resolve<IHelpRelationshipsRepository>();
            usersRepository.DeleteTestEntities();
            helpRelationshipRepository.DeleteTestEntities();
        }

        /// <summary>
        ///A test for GetUserAvatarUrl
        ///</summary>
        [TestMethod()]
        public void GetUserAvatarUrlTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();
            string userID = _users[0].RowKey;
            string expected = _users[0].Avatar;
            string actual;
            actual = target.GetUserAvatarUrl(userID);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for GetHelpedPeopleByUser
        ///</summary>
        [TestMethod()]
        public void GetHelpedPeopleByUserTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();
            string userID = _users[0].RowKey;
            List<User> expected = (from u in _helpedUsers
                                   from hr in _helpRealtionships
                                   where hr.Volunteer == userID && u.RowKey == hr.User
                                   select u).ToList();
            List<User> actual;

            actual = target.GetHelpedPeopleByUser(userID);
            CollectionAssert.AreEquivalent(expected, actual);
        }

        /// <summary>
        ///A test for GetVolunteersOfUser
        ///</summary>
        [TestMethod()]
        public void GetVolunteersOfUserTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();
            string userID = _users[1].RowKey;

            List<User> expected = _volunteers;
            List<User> actual;

            actual = target.GetVolunteersOfUser(userID);
            CollectionAssert.AreEquivalent(expected, actual);
        }

        /// <summary>
        ///A test for GetUserByLiveID
        ///</summary>
        [TestMethod()]
        public void GetUserByLiveIDTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();
            string liveID = _users[0].LiveID;
            User expected = _users[0];
            User actual;
            actual = target.GetUserByLiveID(liveID);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for GetUserFriends
        ///</summary>
        [TestMethod()]
        public void GetUserFriendsTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();

            var friendShipRepository = _unityContainer.Resolve<IFriendshipsRepository>();
            var expected = _usersFactory.CreateList(5);

            foreach(var user in expected)
            {
                target.Add(user);
                friendShipRepository.Add(_users[0].RowKey, user.RowKey);
            }

            string userID = _users[0].RowKey;
            List<User> actual;
            actual = target.GetUserFriends(userID);

            Assert.IsTrue(expected.All(user => actual.Contains(user)));
        }

        /// <summary>
        ///A test for GetUserHospital
        ///</summary>
        [TestMethod()]
        public void GetUserHospitalTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();

            var hospitalsRepository = _unityContainer.Resolve<IHospitalsRepository>();
            var hospitalsPatientsRepository = _unityContainer.Resolve<IHospitalPatientsRepository>();

            var expected = new HospitalsFactory().CreateEntity();
            var hospitalPatient = new HospitalPatient(_users[0].RowKey, expected.RowKey);

            hospitalsRepository.Add(expected);
            hospitalsPatientsRepository.Add(hospitalPatient);

            string userID = _users[0].RowKey;
            Hospital actual;
            actual = target.GetUserHospital(userID);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for IsUserNameUsed
        ///</summary>
        [TestMethod()]
        public void IsUserNameUsedTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();

            string userName = _users[0].RowKey;
            bool expected = true;
            bool actual;
            actual = target.IsUserNameUsed(userName);
            Assert.AreEqual(expected, actual);

            userName = _usersFactory.CreateEntity().RowKey;
            expected = false;
            actual = target.IsUserNameUsed(userName);
            Assert.AreEqual(expected, actual);
        }

        /// <summary>
        ///A test for RecentUsers
        ///</summary>
        [TestMethod()]
        public void RecentUsersTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();

            var users = _usersFactory.CreateList(10);
            users.ForEach(user => target.Add(user));
            users.OrderBy(user => user.Timestamp);

            List<User> actual;
            actual = target.RecentUsers;
            for(int i = 0; i < 10;i++)
            {
                Assert.AreEqual(actual[i], users[i]);
            }
        }

        /// <summary>
        ///A test for Volunteers
        ///</summary>
        [TestMethod()]
        public void VolunteersTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();

            List<User> actual;
            actual = target.Volunteers;
            CollectionAssert.AreEquivalent(_users.Where(u => u.Volunteer).ToList(), actual);
        }

        /// <summary>
        ///A test for GetMessageRecipents
        ///</summary>
        [TestMethod()]
        public void GetMessageRecipentsTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();

            var messagesRepository = _unityContainer.Resolve<IMessagesRepository>();
            var messagesRecipentsRepository = _unityContainer.Resolve<IMessagesRecipentsRepository>();
            var recipents = new List<string> { _users[1].RowKey, _users[2].RowKey, _users[3].RowKey };
            var message = new MessagesFactory().CreateEntity(_users[0].RowKey, recipents);
            messagesRepository.Add(message);

            string messageID = message.RowKey;
            List<User> expected = _users.Skip(1).Take(3).ToList();
            List<User> actual;
            
            actual = target.GetMessageRecipents(messageID);
            CollectionAssert.AreEquivalent(expected, actual);
        }

        /// <summary>
        ///A test for GetUserContainingName
        ///</summary>
        [TestMethod()]
        public void GetUserContainingNameTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();
            var name = "test";
            var expected = _users.Where(u => u.Alias.Contains(name)).ToList();

            var actual = target.GetUserContainingName(name);
            CollectionAssert.AreEquivalent(expected, actual);
        }

        /// <summary>
        ///A test for GetVolunteerByCity
        ///</summary>
        [TestMethod()]
        public void GetVolunteerByCityTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();

            var city = "City A";
            _users[0].City = city;
            _users[1].City = city;
            _users[2].City = city;

            var expected = _users.Take(3).ToList();
            var actual = target.GetVolunteerByCity(city);

            CollectionAssert.AreEquivalent(expected, actual);
        }

        /// <summary>
        ///A test for NonAnonymousUsers
        ///</summary>
        [TestMethod()]
        public void NonAnonymousUsersTest()
        {
            var target = _unityContainer.Resolve<IUsersRepository>();
            var expected = _users.Where(u => !u.Anonymous).ToList();

            var actual = target.NonAnonymousUsers;

            CollectionAssert.AreEquivalent(expected, actual);
        }
    }
}
